#ifndef OBJECT_3D_H
#define OBJECT_3D_H

#include "Engine.h"
#include "../Vertex.h"
#include "btBulletDynamicsCommon.h"
#include "Object3DCollider.h"
#include <iostream>

#define GRAVITY 10.0f

namespace dkm
{
	class Object3D : public Component
	{
	public:
		public:
		//You can specify a texture or a path name to the Sprite.
		//If you don't specify visible and active, they are true by default.
		Object3D(const string xFileSrc, ID3DXEffect* mFX, const D3DXMATRIX* mView, const D3DXMATRIX* mProj, IDirect3DTexture9* mDefaultTex, const float x, const float y, const float z, const float rotateX, const float rotateY, const float rotateZ, const float scaleX, const float scaleY, const float scaleZ, const bool visible, const bool active);
		Object3D(const string xFileSrc, ID3DXEffect* mFX, const D3DXMATRIX* mView, const D3DXMATRIX* mProj, IDirect3DTexture9* mDefaultTex, const float x, const float y, const float z, const float rotateX, const float rotateY, const float rotateZ, const float scaleX, const float scaleY, const float scaleZ);
		virtual ~Object3D();

		void GetHandles(ID3DXEffect* mFX);
		virtual void Update(const float dt) = 0;
		virtual void Draw();
		//Adds a bullet physics rigidbody to the object.
		void AddRigidBody(btDiscreteDynamicsWorld *physicsWorld, const std::string shape, const btVector3 &size, const btVector3 &center, const btScalar mass);
		void AddSphereCollider(const D3DXVECTOR3 &center, const float radius);
		void AddBoxCollider(const D3DXVECTOR3 &center, const float length, const float height, const float width);
		btRigidBody* GetRigidBody() { return thisBody; }
		void CreateTriangleMeshFromMesh(ID3DXMesh *mesh, btTriangleMesh *trimesh);

		void SetID(const std::string id) { this->id = id; }

		void X(const float x) { this->x = x; }
		void Y(const float y) { this->y = y; }
		void Z(const float z) { this->z = z; }
		void RotationX(const float rotationX) { this->rotationX = rotationX; }
		void RotationY(const float rotationY) { this->rotationY = rotationY; }
		void RotationZ(const float rotationZ) { this->rotationZ = rotationZ; }
		void ScaleX(const float scaleX) { this->scaleX = scaleX; }
		void ScaleY(const float scaleY) { this->scaleY = scaleY; }
		void ScaleZ(const float scaleZ) { this->scaleZ = scaleZ; }
		D3DXVECTOR3* Position();
		btVector3* BtVec3Position();
		D3DXVECTOR3* Rotation() const { return &D3DXVECTOR3(rotationX,rotationY,rotationZ); }
		D3DXVECTOR3* Scale() const { return &D3DXVECTOR3(scaleX, scaleY, scaleZ); }
		float X() const { return x; }
		float Y() const { return y; }
		float Z() const { return z; }
		float RotationX() const { return rotationX; }
		float RotationY() const { return rotationY; }
		float RotationZ() const { return rotationZ; }
		float ScaleX() const { return scaleX; }
		float ScaleY() const { return scaleY; }
		float ScaleZ() const { return scaleZ; }
		void AddX(const float x) { this->x += x; }
		void AddY(const float y) { this->y += y; }
		void AddZ(const float z) { this->z += z; }
		void AddRotationX(const float rotationX) { this->rotationX += rotationX; }
		void AddRotationY(const float rotationY) { this->rotationY += rotationY; }
		void AddRotationZ(const float rotationZ) { this->rotationZ += rotationZ; }
		void AddScaleX(const float scaleX) { this->scaleX += scaleX; }
		void AddScaleY(const float scaleY) { this->scaleY += scaleY; }
		void AddScaleZ(const float scaleZ) { this->scaleZ += scaleZ; }
		void ResetPos() { X(0.0f); Y(0.0f); Z(0.0f); }
		void ResetScale() { ScaleX(1.0f); ScaleY(1.0f); ScaleZ(1.0f); }
		void ResetRotation() { RotationX(0.0f); RotationY(0.0f); RotationZ(0.0f); }
		void SetPosition(const float x, const float y, const float z) { X(x); Y(y); Z(z); }
		void SetScale(const float scaleX, const float scaleY, const float scaleZ) { ScaleX(scaleX); ScaleY(scaleY); ScaleZ(scaleZ); }
		void SetRotation(const float rotX, const float rotY, const float rotZ) { RotationX(rotX); RotationY(rotY); RotationZ(rotZ); }
		void Move(const float x, const float y, const float z) { AddX(x); AddY(y); AddZ(z); }
		void PhysicsMove(const btVector3 &movement);
		void PhysicsMove(const D3DXVECTOR3 &movement);
		void Scale(const float scaleX, const float scaleY, const float scaleZ) { AddScaleX(scaleX); AddScaleY(scaleY); AddScaleZ(scaleZ); }
		void Rotate(const float rotX, const float rotY, const float rotZ) { AddRotationX(rotX); AddRotationY(rotY); AddRotationZ(rotZ); }

		bool HasCollider() const { return hasCollider; }
		Object3DCollider* Collider() const { return collider; }
	
	private:
		
		ID3DXEffect* mFX;

		std::string id;

		IDirect3DTexture9* mDefaultTex;

		ID3DXMesh* mMesh;
		std::vector<Mtrl> mMtrl;
		std::vector<IDirect3DTexture9*> mTex;

		D3DXMATRIX worldInvTrans;
		const D3DXMATRIX* mView;
		const D3DXMATRIX* mProj;
		D3DXMATRIX mWorld;

		D3DXHANDLE mhTech;
		D3DXHANDLE mhWVP;
		D3DXHANDLE mhWorldInvTrans;
		D3DXHANDLE mhWorld;
		D3DXHANDLE mhTex;
		D3DXHANDLE mhMtrl;

	protected:

		float x;
		float y;
		float z;
		float rotationX;
		float rotationY;
		float rotationZ;
		float scaleX;
		float scaleY;
		float scaleZ;
		D3DXMATRIX pos;
		D3DXMATRIX rotation;
		D3DXMATRIX scale;

		bool hasPhysics;
		//Bullet physics
		btCollisionShape* colShape;
		btTransform thisTransform;
		btVector3 localInertia;
		btScalar mass;
		btDefaultMotionState *thisMotionState;
		btRigidBody *thisBody;
		btTriangleMesh *trimesh;

		bool hasCollider;
		//Boolean Collisions
		Object3DCollider* collider;			
	};
}

#endif
